package _01grammar

//闭包

//---------闭包基本（闭包是一段代码块，类似于方法）------------
//定义
def clouser = {
    println 'Hello world!!'
}
//调用（使用call调用便于区分是闭包调用）
clouser.call()
//直接调用容易与方法调用混
//clouser()

//带参数 参数->闭包体
def clouser2 = { name, age -> println "Hello ${name},age is ${age}" }
//clouser2("fauks",12)
clouser2.call("groovy", 12)
//闭包中有个默认参数it
def clouser3 = { println "${it}" }
clouser3('clousert3')
clouser3.call('it')

//闭包返回值：闭包中一定有返回值而没有void
//如果没有写return则返回null注意区别于void
def returnClouser = { String name ->
    return "hello ${name}"
}
println returnClouser("return")

//可以省略return语句返回值就是true
def return2 = { true }
//此时返回值为null
def return3 = { println "" }

//------------------------------------------------------------------------------------

//----------闭包的应用------------
//1.闭包与基本类型结合使用
println fab(2)

//计算number的阶乘
int fab(int total) {
    int res = 1
    1.upto(total, {
            //upto方法内部帮我们实现了循环，循环调用我们写的闭包
        num -> res *= num
    })
    return res
}

println fab2(3)
//同样还用downto方法从number开始递减到1
int fab2(int total) {
    int res = 1
    //downto接收两个参数一个Number，一个闭包，在Groovy中闭包如果是最后一个参数可以写在括号后面
    total.downto(1) { num ->
        res *= num
    }
    return res
}

//times 函数循环total次从0开始
void call(int total) {
    total.times { //times方法不需要接收任何参数
        println "hello ${it}"
    }
}

call(3)

//2.闭包与String结合使用
String name = 'fauks23'
//multiply 对字符double
//each 返回name本身
name.each { String it -> print it.multiply(2) }
println ""
//通过find（）、findAll方法找出数字
//find方法返回第一个匹配（此处为数字）：查看源码可知需要闭包返回一个boolean类型
def findNumer = name.find { it.isNumber() }
println "${name} 中第一个数字为 ${findNumer}"
//findAll方法是查询所有符合条件的字符，返回一个集合
def findAllNumber = name.findAll { it.isNumber() }
println findAllNumber.toListString()//将list转换为Stirng
//any every(返回boolean any任何一个满足即可，every所有都满足)
def hasNumber = name.any { it.isNumber() }
println hasNumber
def everyNumber = name.every { it.isNumber() }
println everyNumber

//collection

//------------------------------------------------------------------------------------

//----------闭包的进阶------------
/*
三个重要变量：
    1.this: 同java类似代表闭包定义处的类（脚本编译后生成继承Script的类），此处为当前Groovy脚本对象
    2.owner：代表闭包定义处的类或对象
    3.delegate：任意对象，默认与owner一致
 */
//三者指向的都是此脚本文件所对应的对象（_01grammar._05Closure@71a8adcf）
def outerClouser = {
    println "outerClouser this==>" + this
    println "outerClouser owner==>" + owner
    println "outerClouser delegate==>" + delegate
}
//`outerClouser.call()

println '-------------------------'
//内部类
class User {
    //此处为类中闭包，而且使用static所以代表User的字节码对象（class _01grammar.User）
    static def classClouser = {
        println "classClouser this==>" + this
        println "classClouser owner==>" + owner
        println "classClouser delegate==>" + delegate
    }

    //方法中的闭包代表了User对象（_01grammar.User@d9345cd）
    def say() {
        def methodClouser = {
            println "methodClouser this==>" + this
            println "methodClouser owner==>" + owner
            println "methodClouser delegate==>" + delegate
        }
        methodClouser.call()
    }
}

User.classClouser.call()
new User().say()
println '-------------------------'

//大部分情况下三者指向相同，闭包中的闭包三者含义是否相同？
def oClouser = { oName ->
    def innerClouser = { innerName ->
        //this对象还是指向他默认所在的类（_01grammar._05Closure@514646ef）
        println "innerClouser this==>" + this
        //owner可以指向类或者对象此处闭包定义在另一个闭包对象中所以指向了外部闭包
        //_01grammar._05Closure$_run_closure13@5bf0d49
        println "innerClouser owner==>" + owner
        //在不改变指向的前提下默认与owner指向同一对象或类
        println "innerClouser delegate==>" + delegate
    }
    innerClouser.call()
}

oClouser.resolveStrategy = Closure.DELEGATE_ONLY
oClouser.call()

//闭包委托策略
class Stu {
    String name
    def info = {
        "my name is ${name}"
    }

    String toString() {
        info.call()
    }
}

class Teacher {
    String name
}

Stu stu = new Stu(name: 'fauks')
Teacher teacher = new Teacher(name: 'jay')
//println stu.toString()//在不做任何改变的前提的输出fauks
//改变stu中闭包的delegate
stu.info.delegate = teacher//此时name还是fauks需要改变委托策略
//委托策略(默认为OWNER_FIRST所以如果不知道还输出Stu对象的name)
//此处指定为DELEGATE_FIRST代理优先，如果代理中有则使用没有从原对象的寻找
stu.info.resolveStrategy = groovy.lang.Closure.DELEGATE_FIRST
//println stu.toString()

